/** Fichier implémentant l'interface d'une forme.
 *
 * Ce fichier contient l'implémentation de la classe abstraite Forme.
 *
 * @file Forme.cpp
 * @author Jean-Marc Combi
 * @author Romain Dequesne
 * @author Johan "Solo" Luisier
 *
 * @date 06 Avril 2004
 */
#include "Forme.hpp"

#include "Algebre/Solveur.hpp"

#include "Utils/ATL.hpp"

#include <cmath>

using namespace std;

/**
 * Valeur de \f$ \pi \f$, estimée comme la valeur de l'angle dont le
 * cosinus est \f$ -1 \f$.
 */
const double Forme::ValeurPi( acos( -1. ) );

/** Constructeur permettant d'initialiser une forme.
 *
 * @param nom nom de la forme.
 * @param tr transformation vers les coordonnées globales.
 */
Forme::Forme(const string& nom, const Transformation& tr)
    : VersGlobal( tr ), VersLocal( tr.inverse() ), Nom( nom ),
      MoteurResolution( 0 )
{}

/** Destructeur, virtuel pour assurer une séquence de destruction correcte.
 *
 * Le destructeur doit libérer la mémoire potentiellement allouée pour le
 * solveur d'équation.
 */
Forme::~Forme()
{
    if ( MoteurResolution != 0 )
        delete MoteurResolution;
}

/** Méthode qui permet de savoir si un rayon a une chance d'avoir une
 * intersection avec la forme.
 *
 * On calcule la distance entre le rayon et le PseudoCentre, si cette
 * distance est plus grande que le PseudoRayon, alors il n'y a aucune
 * chance pour qu'une intersection existe.
 *
 * @param[in] rayon instance de Rayon lancé, pur laquelle on veu
 * savoir si une intersection existe.
 *
 * @retval true si le rayon passe à une distance inférieure à
 * PseudoRayon, @retval false sinon.
 */
bool Forme::aIntersection( const Rayon& rayon ) const
{
    Vecteur ab( PseudoCentre, rayon.origine() );

    return ( ab ^ rayon.direction() ) .norme() - puissance< 2u >( PseudoRayon ) < 1.e-7;
}


/** Permet de faire le mapping d'une Texture sur la forme.
 *
 * @warning N'est pas implémenté pour toutes les formes.
 *
 * @param[in] pt point de la surface que l'on veut mapper.
 * @param[out] i coordonnée (x, y?) du pixel attribué au point pt.
 * @param[out] j coordonnée (x, y?) du pixel attribué au point pt.
 * @param[in] frequence répétition du motif
 * @param[in] Hauteur hauteur de l'image.
 * @param[in] Largeur largeur de l'image.
 */
void Forme::mapping(const Coord &pt, int &i, int &j, const int &frequence,
                    const int &Hauteur, const int &Largeur) const
{}

/** Accesseur pour PseudoCentre.
 *
 * Permet de récupérer une estimation grossière de la position de la
 * Forme.
 *
 * @return une référence constante sur PseudoCentre.
 */
const Coord& Forme::pseudoCentre() const
{
    return PseudoCentre;
}

/** Accesseur pour PseudoRayon.
 *
 * Permet de récupérer le rayon de la sphère qui approxime le volume.
 *
 * @return une référence constance sur PseudoRayon.
 */
const double& Forme::pseudoRayon() const
{
    return PseudoRayon;
}
/** Accesseur pour Nom.
 *
 * Permet de récupérer le nom de la Forme.
 *
 * @return une référence constante sur Nom.
 */
const string& Forme::nom() const
{
    return Nom;
}

/** Méthode calculant les coordonnées intrinsèques réduites d'un point de la
 * surface.
 *
 * Cette méthode permet de récupérer un point de la surface dans les
 * coordonnées intrinsèques, mais avec un traitement supplémentaire qui permet
 * de calculer aisément la couleur du damier à plaquer sur la surface.
 *
 * Pour la majorité des Formes, il suffit de renvoyer les coordonnées
 * intrinsèques, une fois divisées par larg. Pour les formes avec une
 * périodicité c'est plus compliqué.
 *
 * @param[in] pt point de la surface dont on aimerait les coordonnées
 * "réduites" à deux entiers.
 * @param[in] larg largeur des carreaux désirés.
 *
 * @return une variante des coordonnées intrinsèques de @c pt, sous la
 * forme d'une Coord dont la composante z est nulle.
 */
Coord Forme::intrinsequeReduite(const Coord& pt, const double& larg) const
{
    return intrinseque( pt ) / larg;
}

/** Accesseur pour VersLocal.
 *
 * Permet d'accéder à la transformation vers les coordonnées locales.
 *
 * @return une référence constante sur VersLocal.
 */
const Transformation& Forme::versLocal() const
{
    return VersLocal;
}

/** Accesseur pour VersGlobal.
 *
 * Permet d'accéder à la transformation vers les coordonnées globales.
 *
 * @return une référence constante sur VersGlobal.
 */
const Transformation& Forme::versGlobal() const
{
    return VersGlobal;
}
